/*
 * lexical_cast.h
 *
 *  Created on: 2008-9-25
 *      Author: fanliangliang
 */

#ifndef LEXICAL_CAST_H_
#define LEXICAL_CAST_H_

#include "config.h"
#include <string>
#include <sstream>
#include <iomanip>
#include <exception>
#include <typeinfo>

BEGIN_NAMESPACE_TOXIC

// exception used to indicate runtime lexical_cast failure
class bad_lexical_cast: public std::bad_cast {
public:
	template <typename SourceType>
	bad_lexical_cast(const std::type_info& targetType, const SourceType& value)
	:_what() {
		std::ostringstream oss;
		oss << "bad lexical cast: can not interpret '" << nameOf(typeid(SourceType)) << "' as '"
			<< nameOf(targetType) << "' [with value = \"" << value << "\"]";
		_what = oss.str();
	}

	virtual const char* what() const throw() {
		return _what.c_str();
	}

	virtual ~bad_lexical_cast() throw() {
	}

private:
	static const char* nameOf(const std::type_info& type) {
		if (type == typeid(bool)) {
			return "bool";
		} else if (type == typeid(char)) {
			return "char";
		} else if (type == typeid(signed char)) {
			return "signed char";
		} else if (type == typeid(unsigned char)) {
			return "unsigned char";
		} else if (type == typeid(wchar_t)) {
			return "wchar_t";
		} else if (type == typeid(short)) {
			return "short";
		} else if (type == typeid(unsigned short)) {
			return "unsigned short";
		} else if (type == typeid(int)) {
			return "int";
		} else if (type == typeid(unsigned int)) {
			return "unsigned int";
		} else if (type == typeid(long)) {
			return "long";
		} else if (type == typeid(unsigned long)) {
			return "unsigned long";
		} else if (type == typeid(long long)) {
			return "long long";
		} else if (type == typeid(unsigned long long)) {
			return "unsigned long long";
		} else if (type == typeid(float)) {
			return "float";
		} else if (type == typeid(double)) {
			return "double";
		} else if (type == typeid(long double)) {
			return "long double";
		} else {
			return "string";
		}
	}

private:
	std::string _what;
};


template <typename TargetType, typename SourceType>
TargetType lexical_cast(const SourceType& value) {
	TargetType target;
	std::stringstream strm;
	strm << std::boolalpha << value;
	strm >> target >> std::noboolalpha;

	if (!strm) {
		throw bad_lexical_cast(typeid(TargetType), value);
	}
	return target;
}

END_NAMESPACE_TOXIC

#endif /* LEXICAL_CAST_H_ */
